﻿using Microsoft.AspNetCore.Http;
using SequentialGuid;
using System.Reflection.Emit;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using WCS.Infrastructure.Dto.Models.Order;
using WCS.Infrastructure.Dto.Request.ReportForm;

namespace WCS.Infrastructure.Tools
{

    public class LatLng
    {
        public LatLng(double x, double y)
        {
            latitude = x;
            longitude = y;
        }
        public double latitude;
        public double longitude;
    }

    /// <summary>
    /// 配置文件操作类
    /// </summary>
    public class Config
    {
        private readonly static Random rd = new();

        // 一周的起始日（可根据业务调整，这里以周一为起始）
        private const DayOfWeek WeekStartDay = DayOfWeek.Monday;

        //地球半径，单位米
        private const double EARTH_RADIUS = 6378137;
        /// <summary>
        /// 计算两点位置的距离，返回两点的距离，单位 米
        /// 该公式为GOOGLE提供，误差小于0.2米
        /// </summary>
        /// <param name="lat1">第一点纬度</param>
        /// <param name="lng1">第一点经度</param>
        /// <param name="lat2">第二点纬度</param>
        /// <param name="lng2">第二点经度</param>
        /// <returns></returns>
        public static double GetDistance(double lat1, double lng1, double lat2, double lng2)
        {
            double radLat1 = Rad(lat1);
            double radLng1 = Rad(lng1);
            double radLat2 = Rad(lat2);
            double radLng2 = Rad(lng2);
            double a = radLat1 - radLat2;
            double b = radLng1 - radLng2;
            double result = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2))) * EARTH_RADIUS;
            return result;
        }

        /// <summary>
        /// 经纬度转化成弧度
        /// </summary>
        /// <param name="d"></param>
        /// <returns></returns>
        private static double Rad(double d)
        {
            return (double)d * Math.PI / 180d;
        }

        /// <summary>
        /// 判断两个经纬度的距离
        /// </summary>
        /// <param name="j1">第一个经度</param>
        /// <param name="w1">第一个纬度</param>
        /// <param name="j2">第二个经度</param>
        /// <param name="w2">第二个纬度</param>
        /// <returns></returns>
        public static double GetGreatCircleDistance(double j1, double w1, double j2, double w2)
        {
            LatLng start = new(j1, w1);
            LatLng end = new(j2, w2);

            double lat1 = (Math.PI / 180) * start.latitude;
            double lat2 = (Math.PI / 180) * end.latitude;

            double lon1 = (Math.PI / 180) * start.longitude;
            double lon2 = (Math.PI / 180) * end.longitude;

            double r = 6371000; //地球半径(米)

            double dd = Math.Acos(Math.Sin(lat1) * Math.Sin(lat2) + Math.Cos(lat1) * Math.Cos(lat2) * Math.Cos(lon2 - lon1)) * r;
            return dd;
        }

        /// <summary>
        /// 获取随机数
        /// </summary>
        /// <param name="min">最小值 包含</param>
        /// <param name="max">最大值 不包含</param>
        /// <returns></returns>
        public static int GetRandom(int min, int max)
        {
            return rd.Next(min, max);
        }

        /// <summary>
        /// 获取时间戳
        /// </summary>
        /// <returns></returns>
        public static long GetTimeStamp()
        {

            return (DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
        }

        /// <summary>
        /// 获取请求IP
        /// </summary>
        public static string GetIp()
        {
            //return "127.0.0.1";//正式环境请注释
            //IHttpContextAccessor _httpContextAccessor = new HttpContextAccessor();
            //return _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();//测试环境请注释

            IHttpContextAccessor _httpContextAccessor = new HttpContextAccessor();
            var remoteIpAddress = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress;

            if (remoteIpAddress != null)
            {
                string ipString = remoteIpAddress.ToString();

                // 处理IPv4映射的IPv6地址格式 (::ffff:x.x.x.x)
                if (ipString.StartsWith("::ffff:"))
                {
                    return ipString.Substring(7); // 去掉"::ffff:"前缀
                }

                return ipString;
            }

            return "127.0.0.1"; // 默认返回本地IP
        }

        /// <summary>
        /// 获取IPv6地址
        /// </summary>
        public static string GetIPv6()
        {
            IHttpContextAccessor _httpContextAccessor = new HttpContextAccessor();
            var remoteIpAddress = _httpContextAccessor.HttpContext.Connection.RemoteIpAddress;

            if (remoteIpAddress != null)
            {
                // 如果是IPv6地址或IPv4映射的IPv6地址，直接返回
                if (remoteIpAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetworkV6)
                {
                    return remoteIpAddress.ToString();
                }
                // 如果是IPv4地址，转换为IPv4映射的IPv6格式
                else if (remoteIpAddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
                {
                    return $"::ffff:{remoteIpAddress}";
                }
            }

            return "::1"; // IPv6本地地址
        }

        /// <summary>
        /// 生成GUID（有序的）
        /// </summary>
        /// <returns></returns>
        public static string GUID()
        {
            return SequentialGuidGenerator.Instance.NewGuid().ToString("N");
            //return Guid.NewGuid().ToString().Replace("-", "");
        }

        /// <summary>
        /// 生成编号
        /// </summary>
        /// <returns></returns>
        public static string GenerateCode(string prefix = "")
        {
            string timestamp = "";
            //if (prefix == "MER")//商户编号
            //{
            //    timestamp = DateTime.Now.ToString("yyMMddHHmmssfff");
            //}
            //if (prefix == "STO")//门店编号
            //{
            //    timestamp = DateTime.Now.ToString("yyMMddHHmmssfff");
            //}
            //if (prefix == "ORD")//订单编号
            //{
            //    timestamp = DateTime.Now.ToString("yyMMddHHmmssfff");
            //}
            //if (prefix == "CT")//优惠券模板编号
            //{
            //    timestamp = DateTime.Now.ToString("yyMMddHHmmssfff");
            //}
            //if (prefix == "CI")//优惠券实例编号
            //{
            //    prefix = "";
            //    timestamp = DateTime.Now.ToString("yyMMddHHmmssfff");
            //}
            //if (prefix == "SET")//结算记录编号
            //{
            //    timestamp = DateTime.Now.ToString("yyMMddHHmmssfff");
            //}
            //if (prefix == "P")//支付平台编号
            //{
            //    timestamp = DateTime.Now.ToString("yyMMddHHmmss");
            //}
            //if (prefix == "")
            //{
            //    timestamp = DateTime.Now.ToString("yyMMddHHmmssfff");
            //}
            timestamp = DateTime.Now.ToString("yyMMddHHmm");
            var number = GenerateUniqueFourDigitString();
            timestamp = timestamp + number;
            return $"{prefix}{timestamp}";

            // 检查是否需要重置计数器（跨天）
            //if (DateTime.Today != _currentDate)
            //{
            //    Interlocked.Exchange(ref _merchantDailyCounter, 0);
            //    _currentDate = DateTime.Today;
            //}

            //// 获取当日递增的序列号（原子操作，线程安全）
            //int sequence = Interlocked.Increment(ref _merchantDailyCounter);

            //// 格式化为6位数字（如0001）
            //string formattedSeq = sequence.ToString("D6");

            //// 组合：前缀 + 日期 + 序列号
            //return $"{prefix}{DateTime.Today:yyyyMMdd}{formattedSeq}";
        }

        private static readonly HashSet<string> _generated = new HashSet<string>();

        // 替换全局唯一集合，改为时间片内的原子递增序列，避免耗尽后死循环
        private static int _fourDigitSequence = -1;
        private static DateTime _fourDigitSequencePeriod = DateTime.UtcNow;
        private static readonly object _fourDigitSequenceLock = new object();
        
        public static string GenerateUniqueFourDigitString()
        {
            var now = DateTime.UtcNow;
            // 当时间片（按分钟）变化时，重置序列
            if (now.Minute != _fourDigitSequencePeriod.Minute || now.Hour != _fourDigitSequencePeriod.Hour || now.Day != _fourDigitSequencePeriod.Day)
            {
                lock (_fourDigitSequenceLock)
                {
                    var check = DateTime.UtcNow;
                    if (check.Minute != _fourDigitSequencePeriod.Minute || check.Hour != _fourDigitSequencePeriod.Hour || check.Day != _fourDigitSequencePeriod.Day)
                    {
                        _fourDigitSequence = -1;
                        _fourDigitSequencePeriod = check;
                    }
                }
            }
        
            // 原子递增，避免并发冲突
            var next = System.Threading.Interlocked.Increment(ref _fourDigitSequence);
        
            // 超过9999后进行安全回绕，避免异常或死循环
            if (next >= 10000)
            {
                lock (_fourDigitSequenceLock)
                {
                    if (_fourDigitSequence >= 10000)
                    {
                        _fourDigitSequence = 0; // 回绕
                        _fourDigitSequencePeriod = DateTime.UtcNow; // 更新时间片
                        next = 0;
                    }
                    else
                    {
                        next = _fourDigitSequence;
                    }
                }
            }
        
            return next.ToString("D4");
        }

        /// <summary>
        /// 按日获取区间（当天00:00:00 至 23:59:59.999）
        /// </summary>
        public static DateTimeRequestDto GetDayRange(DateTime baseDate)
        {
            DateTime start = baseDate.Date; // 00:00:00
            DateTime end = start.AddDays(1).AddTicks(-1); // 23:59:59.999
            return new DateTimeRequestDto
            {
                StartTime = start,
                EndTime = end,
            };
        }

        /// <summary>
        /// 按周获取区间（周起始日00:00:00 至 周结束日23:59:59.999）
        /// </summary>
        public static DateTimeRequestDto GetWeekRange(DateTime baseDate)
        {
            // 计算当前日期距离周起始日的偏移天数
            int offset = (baseDate.DayOfWeek - WeekStartDay + 7) % 7;
            DateTime firstDayOfWeek = baseDate.AddDays(-offset).Date; // 周起始日（如周一）
            DateTime lastDayOfWeek = firstDayOfWeek.AddDays(6); // 周结束日（如周日）

            DateTime start = firstDayOfWeek; // 00:00:00
            DateTime end = lastDayOfWeek.Date.AddDays(1).AddTicks(-1); // 23:59:59.999
            return new DateTimeRequestDto
            {
                StartTime = start,
                EndTime = end,
            };
        }


        /// <summary>
        /// 按月获取区间（当月1日00:00:00 至 当月最后一天23:59:59.999）
        /// </summary>
        public static DateTimeRequestDto GetMonthRange(DateTime baseDate)
        {
            DateTime firstDayOfMonth = new DateTime(baseDate.Year, baseDate.Month, 1); // 当月1日
            DateTime firstDayOfNextMonth = firstDayOfMonth.AddMonths(1); // 下月1日
            DateTime lastDayOfMonth = firstDayOfNextMonth.AddDays(-1); // 当月最后一天

            DateTime start = firstDayOfMonth.Date; // 00:00:00
            DateTime end = lastDayOfMonth.Date.AddDays(1).AddTicks(-1); // 23:59:59.999
            return new DateTimeRequestDto
            {
                StartTime = start,
                EndTime = end,
            };
        }

        /// <summary>
        /// 获取近N天的日区间列表（含今天，共N个区间）
        /// </summary>
        public static List<DateTimeRequestDto> GetRecentDays(DateTime baseDate, int days = 7)
        {
            var ranges = new List<DateTimeRequestDto>();
            for (int i = 0; i < days; i++)
            {
                DateTime targetDate = baseDate.AddDays(-i);
                ranges.Add(GetDayRange(targetDate));
            }
            return ranges.OrderBy(r => r.StartTime).ToList();
        }

        /// <summary>
        /// 获取指定开始日期和结束日期之间的日区间列表（包含开始和结束日期）
        /// </summary>
        /// <param name="startDate">开始日期</param>
        /// <param name="endDate">结束日期</param>
        /// <returns>日期区间列表，按时间顺序排列</returns>
        public static List<DateTimeRequestDto> GetDateRangeList(DateTime startDate, DateTime endDate)
        {
            var ranges = new List<DateTimeRequestDto>();

            // 确保开始日期不晚于结束日期
            if (startDate > endDate)
            {
                // 交换开始和结束日期
                (startDate, endDate) = (endDate, startDate);
            }

            // 只取日期部分，忽略时间
            DateTime currentDate = startDate.Date;
            DateTime endDateOnly = endDate.Date;

            // 遍历从开始日期到结束日期的每一天
            while (currentDate <= endDateOnly)
            {
                ranges.Add(GetDayRange(currentDate));
                currentDate = currentDate.AddDays(1);
            }

            return ranges;
        }

        /// <summary>
        /// 获取前N周的区间（含当前周，如近4周则共4个区间）
        /// </summary>
        public static List<DateTimeRequestDto> GetRecentWeeks(DateTime baseDate, int weeks = 4)
        {
            var ranges = new List<DateTimeRequestDto>();
            for (int i = 0; i < weeks; i++)
            {
                DateTime targetDate = baseDate.AddDays(-i * 7);
                ranges.Add(GetWeekRange(targetDate));
            }
            return ranges.OrderBy(r => r.StartTime).ToList();
        }

        /// <summary>
        /// 获取前N月的月区间（含当前月，半年共6个区间）
        /// </summary>
        public static List<DateTimeRequestDto> GetRecent6Months(DateTime baseDate, int months = 6)
        {
            var ranges = new List<DateTimeRequestDto>();
            for (int i = 0; i < months; i++)
            {
                DateTime targetDate = baseDate.AddMonths(-i);
                ranges.Add(GetMonthRange(targetDate));
            }
            return ranges.OrderBy(r => r.StartTime).ToList();
        }

        /// <summary>
        /// 通用对象序列化为JSON方法
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="obj">要序列化的对象</param>
        /// <returns>JSON字符串</returns>
        public static string SerializeToJson<T>(T obj)
        {
            try
            {
                if (obj == null)
                {
                    return "{}";
                }

                return System.Text.Json.JsonSerializer.Serialize(obj, new JsonSerializerOptions
                {
                    PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
                    WriteIndented = false,
                    DefaultIgnoreCondition = JsonIgnoreCondition.Never,
                    //Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping // 添加这行避免Unicode转义
                });
            }
            catch (Exception ex)
            {
                return "{}";
            }
        }

        /// <summary>
        /// 通用JSON反序列化为对象方法
        /// </summary>
        /// <typeparam name="T">目标对象类型</typeparam>
        /// <param name="jsonString">JSON字符串</param>
        /// <returns>反序列化后的对象</returns>
        public static T? DeserializeFromJson<T>(string jsonString) where T : class
        {
            try
            {
                if (string.IsNullOrEmpty(jsonString))
                {
                    return null;
                }

                return System.Text.Json.JsonSerializer.Deserialize<T>(jsonString, new JsonSerializerOptions
                {
                    PropertyNameCaseInsensitive = true
                });
            }
            catch (Exception ex)
            {
                return null;
            }
        }

        /// <summary>
        /// 支付状态转换
        /// </summary>
        /// <param name="payState"></param>
        /// <returns></returns>
        public static int PaymentStatusTransition(string payState)
        {
            if (payState == "00")//支付成功
                return 1;
            if (payState == "01")//失败
                return 2;
            if (payState == "03")//处理中
                return 0;
            if (payState == "05")//撤销
                return 3;
            if (payState == "06")//关闭
                return 4;

            return 0;
        }

        /// <summary>
        /// 解析时间字符串为DateTime对象
        /// </summary>
        /// <param name="timeString">时间字符串</param>
        /// <param name="format">时间格式，默认为"yyyyMMddHHmmss"</param>
        /// <returns>解析后的DateTime对象，如果解析失败则返回当前时间</returns>
        public static DateTime ParseTimeString(string timeString, string format = "yyyyMMddHHmmss")
        {
            if (string.IsNullOrWhiteSpace(timeString))
            {
                return DateTime.Now;
            }

            DateTime result = DateTime.Now;
            DateTime.TryParseExact(timeString, format, null, System.Globalization.DateTimeStyles.None, out result);
            return result;
        }

        /// <summary>
        /// 生成指定长度的随机字符串
        /// </summary>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string GenerateRandomKey(int length)
        {
            const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            StringBuilder res = new StringBuilder();
            byte[] randomBytes = new byte[length];

            using (RandomNumberGenerator rng = RandomNumberGenerator.Create())
            {
                rng.GetBytes(randomBytes);
            }

            for (int i = 0; i < length; i++)
            {
                res.Append(valid[randomBytes[i] % valid.Length]);
            }

            return res.ToString();
        }


        /// <summary>
        /// 将分账结果状态码转换为分账状态
        /// </summary>
        /// <param name="splitState">分账结果状态码（00=分账成功，01=分账失败，03=处理中，04=预分帐成功，05=已撤销，51=待处理）</param>
        /// <returns>分账状态（0=处理中,1=分账成功,2=分账失败,3=预分帐成功，4=已撤销，5=待处理）</returns>
        public static int ConvertSplitStateToSplitStatus(string splitState)
        {
            return splitState switch
            {
                "00" => 1, // 分账成功
                "01" => 2, // 分账失败
                "03" => 0, // 处理中
                "04" => 3, // 预分帐成功
                "05" => 4, // 已撤销
                "51" => 5, // 待处理
                _ => 0     // 默认为处理中
            };
        }

        /// <summary>
        /// 根据PayState值转换为WithdrawalStatus值
        /// </summary>
        /// <param name="payState">支付状态字符串（00=成功，01=失败，03=处理中，04=延迟处理中）</param>
        /// <returns>提现状态整型（0=处理中，1=成功，2=失败，3=延迟处理中）</returns>
        public static int ConvertPayStateToWithdrawalStatus(string payState)
        {
            return payState switch
            {
                "00" => 1, // 成功
                "01" => 2, // 失败
                "03" => 0, // 处理中
                "04" => 3, // 延迟处理中
                _ => 0     // 默认为处理中
            };
        }


        /// <summary>
        /// 身份证号脱敏处理
        /// </summary>
        /// <param name="idCardNo">身份证号</param>
        /// <returns>脱敏后的身份证号</returns>
        public static string MaskIdCardNo(string idCardNo)
        {
            if (string.IsNullOrEmpty(idCardNo) || idCardNo.Length != 18)
            {
                return idCardNo;
            }

            // 保留前6位（地区码）和后2位，中间10位用*号替代
            // 格式：123456**********01
            var firstPart = idCardNo.Substring(0, 6);
            var lastPart = idCardNo.Substring(16, 2);
            var maskPart = new string('*', 10);

            return $"{firstPart}{maskPart}{lastPart}";
        }

        /// <summary>
        /// 银行卡号脱敏处理
        /// </summary>
        /// <param name="bankCardNo">银行卡号</param>
        /// <returns>脱敏后的银行卡号</returns>
        public static string MaskBankCardNo(string bankCardNo)
        {
            if (string.IsNullOrEmpty(bankCardNo) || bankCardNo.Length < 8)
            {
                return bankCardNo;
            }

            // 保留前4位和后4位，中间用*号替代
            var firstPart = bankCardNo.Substring(0, 4);
            var lastPart = bankCardNo.Substring(bankCardNo.Length - 4);
            var maskLength = bankCardNo.Length - 8;
            var maskPart = new string('*', maskLength);

            return $"{firstPart}{maskPart}{lastPart}";
        }

        /// <summary>
        /// 生成安全的6位数字验证码
        /// </summary>
        public static string GenerateSecureVerificationCode()
        {
            using (var rng = RandomNumberGenerator.Create())
            {
                var bytes = new byte[4];
                rng.GetBytes(bytes);
                // 生成一个0~999999之间的随机数
                int value = BitConverter.ToInt32(bytes, 0) & 0x7FFFFFFF;
                int code = value % 1000000;
                return code.ToString("D6");
            }
        }

        /// <summary>
        /// 生成安全的8位数字密码
        /// </summary>
        /// <returns></returns>
        public static string GenerateSecurePassword()
        {
            return "123456";
            using (var rng = RandomNumberGenerator.Create())
            {
                var bytes = new byte[4];
                rng.GetBytes(bytes);
                // 生成一个0~999999之间的随机数
                int value = BitConverter.ToInt32(bytes, 0) & 0x7FFFFFFF;
                int code = value % 1000000;
                return code.ToString("D8");
            }
        }


        /// <summary>
        /// 手机号中间脱敏方法（支持多国号码格式）
        /// </summary>
        /// <param name="phoneNumber">原始手机号</param>
        /// <param name="maskChar">脱敏字符（默认*）</param>
        /// <param name="keepLeft">保留左侧位数（默认3）</param>
        /// <param name="keepRight">保留右侧位数（默认4）</param>
        /// <returns>脱敏后的手机号</returns>
        public static string MaskPhoneNumber(
            string phoneNumber,
            char maskChar = '*',
            int keepLeft = 3,
            int keepRight = 4)
        {
            if (string.IsNullOrWhiteSpace(phoneNumber))
                return phoneNumber;

            // 清除非数字字符
            var cleanNumber = Regex.Replace(phoneNumber, @"\D", "");

            // 根据长度动态处理
            int totalLength = cleanNumber.Length;
            int maskCount = totalLength - keepLeft - keepRight;

            if (maskCount <= 0)
            {
                // 号码过短时全保留
                return cleanNumber;
            }

            // 构建脱敏字符串
            var maskedPart = new string(maskChar, maskCount);
            return $"{cleanNumber.Substring(0, keepLeft)}{maskedPart}{cleanNumber.Substring(cleanNumber.Length - keepRight)}";
        }

        /// <summary>
        /// 手机号中间脱敏(使用正则表达式实现)
        /// </summary>
        /// <param name="phoneNumber"></param>
        /// <param name="maskChar"></param>
        /// <returns></returns>
        public static string MaskPhoneNumberRegex(
            string phoneNumber,
            char maskChar = '*')
        {
            if (string.IsNullOrWhiteSpace(phoneNumber))
                return phoneNumber;

            return Regex.Replace(phoneNumber, @"(\d{3})\d{4}(\d{4})",
                m => $"{m.Groups[1].Value}{new string(maskChar, 4)}{m.Groups[2].Value}");
        }

        /*
        // 基础用法
        var masked = PhoneMasker.MaskPhoneNumber("13812345678");
        // 输出：138****5678

        // 自定义保留位数
        var customMask = PhoneMasker.MaskPhoneNumber("13812345678", keepLeft: 2, keepRight: 3);
        // 输出：13****678

        // 处理带分隔符的号码
        var international = PhoneMasker.MaskPhoneNumber("+86 138 1234 5678");
        // 输出：+86 138****5678

        // 正则表达式版本
        var regexMask = PhoneMasker.MaskPhoneNumberRegex("13812345678");
        // 输出：138****5678
        */
    }
}
